package com.yyy.spring6.aop.annoaop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Project ：learn_spring
 * @File ：LogAspect.java
 * @IDE ：IntelliJ IDEA
 * @Author ：自由如风间
 * @Date ：2025/4/3 11:06
 * @Description ：切面类，测试通知方法
 */

// 切面类
@Aspect
@Component // ioc容器
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(LogAspect.class);

    // 前置通知
    @Before(value = "execution(public int com.yyy.spring6.aop.annoaop.CalculatorImpl.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        // 很奇怪，这个log没有输出到终端
        // logger.info("前置通知");
        // idea里面的vim插件太智能了，反而在注释里面使用不了 yi(
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("前置通知，方法名：" + methodName + "，参数：" + Arrays.toString(args));
    }

    // 重用案例
    @After("pointCut()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("后置通知，方法名：" + methodName);
    }

    @AfterReturning(value = "execution(* com.yyy.spring6.aop.annoaop.CalculatorImpl.*(..))", returning = "result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("返回通知，方法名：" + methodName);
    }

    // 异常通知，只有在捕获到异常的时候才会执行
    @AfterThrowing(value = "execution(* com.yyy.spring6.aop.annoaop.CalculatorImpl.*(..))", throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("异常通知，方法名：" + methodName + "，异常信息：" + ex);
    }

    @Around(value = "execution(* com.yyy.spring6.aop.annoaop.CalculatorImpl.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argString = Arrays.toString(args);
        Object result = null;
        try {
            System.out.println("环绕通知，在目标方法之前执行");
            // 调用目标方法
            result = joinPoint.proceed();
            System.out.println("环绕通知，在目标方法之后执行");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知，在目标方法出现异常之后执行");
        } finally {
            System.out.println("环绕通知，在目标方法执行完毕后执行");
        }
        return result;
    }

    // 重用切入表达式
    @Pointcut("execution(* com.yyy.spring6.aop.annoaop.CalculatorImpl.*(..))")
    public void pointCut() {}
}
